package etf.db40;

import java.util.Random;

import com.db4o.ObjectSet;
import com.db4o.query.Query;

import etf.library.*;


public class IntermediateDb4o extends Db4oUtil{
	final static String DB4OFILENAME = "IntermediateTest";
	
	public IntermediateDb4o(){
		createDatabase(DB4OFILENAME);
	}
	public IntermediateDb4o(String fileName){
		createDatabase("/" + fileName + ".db40");
	}
	
	public long insert(int brojSlogova){
		long elapsedTime = 0;
		
		try {
			long startTime = System.currentTimeMillis();
			for (int i = 0; i < brojSlogova; i++) {
				Address address = new Address("Splitska " + i ,i, "Sarajevo", i, "BiH");
				Employee emp = new Employee("John_"+i,"Doe_"+i,i,1500,address);
				db.store(emp);
			}
			db.commit();
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
		} catch (Exception e) {
			e.printStackTrace();
			db.close();
		}		
		return elapsedTime;
	}
	
	public long query(final int brojSlogova){
		long elapsedTime = 0;
		double suma = 0;
		try {
			
			for (int i = 0; i < 4; i++) {
				long startTime = System.currentTimeMillis();
				Query q = db.query();
				q.constrain(Employee.class);
				q.descend("address").descend("houseNumber").constrain(
						getRandom(brojSlogova));
				ObjectSet<Employee> result = q.execute();
				if (result.hasNext()) {
					Employee e = result.next();
					System.out.println(e.getFirstName());
				}
				long stopTime = System.currentTimeMillis();
				elapsedTime = stopTime - startTime;
				suma +=elapsedTime;
			}
			suma = suma/4;
		} catch (Exception e) {
			e.printStackTrace();
			db.close();
		}
		return (long) suma;
	}
	
	public long indexedQuery(int brojSlogova){
		long elapsedTime = 0;
		double suma = 0;
		try {			
			for (int i = 0; i < 5; i++) {
				long startTime = System.currentTimeMillis();
				Query q = db.query();
				q.constrain(Employee.class);
				q.descend("address").descend("zipPostCode").constrain(
						getRandom(brojSlogova));
				ObjectSet<Employee> result = q.execute();
				if (result.hasNext()) {
					Employee e = result.next();
					System.out.println(e.getFirstName());
				}
				long stopTime = System.currentTimeMillis();
				elapsedTime = stopTime - startTime;
				suma +=elapsedTime;
			}
			
			suma = suma/5;
		} catch (Exception e) {
			e.printStackTrace();
			db.close();
		}
		return (long) suma;
	}
	
	public long update(int size){
		long elapsedTime = 0;
		try {
			long startTime = System.currentTimeMillis();
			Query q = db.query();
			q.constrain(Employee.class);
			q.descend("address").descend("zipPostCode").constrain(getRandom(size));
			ObjectSet<Employee> result = q.execute();
			if(result.hasNext()){
				Employee e = result.next();
				e.setFirstName("New_name");
				db.store(e);
				db.commit();
			}
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
		} catch (Exception e) {
			e.printStackTrace();
			db.close();
		}
		return elapsedTime;
	}
	
	public long delete(int size) {
		long elapsedTime = 0;
		try {
			long startTime = System.currentTimeMillis();
			Query q = db.query();
			q.constrain(Employee.class);
			q.descend("address").descend("houseNumber").constrain(getRandom(size));
			ObjectSet<Employee> result = q.execute();
			if(result.hasNext()){
				db.delete(result.next());
			}
			db.commit();
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
		} catch (Exception e) {
			e.printStackTrace();
			db.close();
		}
		return elapsedTime;
	}
	
	public long indexedDelete(int size) {
		long elapsedTime = 0;
		double suma = 0;
		try {
			for (int i = 0; i < 4; i++) {
				long startTime = System.currentTimeMillis();
				Query q = db.query();
				q.constrain(Employee.class);
				q.descend("address").descend("zipPostCode").constrain(
						getRandom(size));
				ObjectSet<Employee> result = q.execute();
				if (result.hasNext()) {
					db.delete(result.next());
				}
				db.commit();
				long stopTime = System.currentTimeMillis();
				elapsedTime = stopTime - startTime;
				suma += elapsedTime;
			}
			suma = suma/4;
		} catch (Exception e) {
			e.printStackTrace();
			db.close();
		}
		return (long)suma;
	}
	// -------------------------------------------------------------------------------------------
	//											1 to N
	//-------------------------------------------------------------------------------------------
	
	
	public long insert_1_to_N(int brojSlogova){
		long elapsedTime = 0;
		try {
			long startTime = System.currentTimeMillis();
			
			Category cat = new Category("Drama");
			for (int i = 0; i < brojSlogova/100; i++) {
				Author author = new Author("Peter_"+i, "Lacko_" +i, "Male", i);
				for (int j = 0; j < 100; j++) {
					Book book = new Book("Book_" + j, i*100 + j, cat, author);
					author.addBook(book);
				}
				db.store(author);
			}
			db.commit();
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
		} catch (Exception e) {
			e.printStackTrace();
			db.close();
		}		
		return elapsedTime;
	}
	
	public long query_1_to_N(int size) {
		long elapsedTime = 0;

		try {
			
			long startTime = System.currentTimeMillis();
			Query q = db.query();
			q.constrain(Author.class);
			q.descend("books").descend("year").constrain(getRandom(size));
			ObjectSet<Author> result = q.execute();
			if (result.hasNext()) {
				Author a = result.next();
				System.out.println("2: " + a.getFirstName());
			}
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
		
		} catch (Exception e) {
			e.printStackTrace();
			db.close();
		}
		return elapsedTime;
	}
	
	public long update_1_to_N(int size) {
		long elapsedTime = 0;
		try {
			long startTime = System.currentTimeMillis();
			
			Query q = db.query();
			q.constrain(Author.class);
			q.descend("books").descend("year").constrain(getRandom(size));
			ObjectSet<Author> result = q.execute();
			if (result.hasNext()) {
				Author a = result.next();
				a.setFirstName("New_name");
				db.store(a);
				db.commit();
				System.out.println("2: " + a.getFirstName());
			}

			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
		} catch (Exception e) {
			e.printStackTrace();
			db.close();
		}
		return elapsedTime;
	}
	
	public long delete_1_to_N(int size) {
		long elapsedTime = 0;
		try {
			long startTime = System.currentTimeMillis();
			
			Query q = db.query();
			q.constrain(Author.class);
			q.descend("books").descend("year").constrain(getRandom(size));
			ObjectSet<Author> result = q.execute();
			if (result.hasNext()) {
				Author a = result.next();
				db.delete(a);
				db.commit();
			}
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
		} catch (Exception e) {
			e.printStackTrace();
			db.close();
		}
		return elapsedTime;
	}
	
	// -------------------------------------------------------------------------------------------
	//											N to N
	//-------------------------------------------------------------------------------------------
	
	public long insert_N_to_N(int size){
		long elapsedTime = 0;
		try {
			long startTime = System.currentTimeMillis();
			Author author = new Author("Peter", "Lacko", "Male", 44);
			Category cat = new Category("Drama");
			
			for (int j = 0; j < size / 100; j++) {
				Member member = new Member("Mark_"+j, "Twain_"+j, j, "gmail");
				for (int i = 0; i < 100; i++) {
					int temp = j*100+i;
					Book book = new Book("Book_"+temp, i, cat, author);
					member.rentABook(book);
					book.addRenter(member);
				}
				db.store(member);
			}
			db.commit();
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
		} catch (Exception e) {
			e.printStackTrace();
			db.close();
		}		
		return elapsedTime;
	}
	
	public long query_N_to_N(int brojSlogova) {
		long elapsedTime = 0;
		try {
			long startTime = System.currentTimeMillis();
			
			Query q = db.query();
			q.constrain(Member.class);
			q.descend("rentedBooks").descend("year").constrain(getRandom(100));
			ObjectSet<Member> result = q.execute();
			if (result.hasNext()) {
				Member m = result.next();
			}
			
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
		} catch (Exception e) {
			e.printStackTrace();
			db.close();
		}
		return elapsedTime;
	}
	
	public long update_N_to_N(int brojSlogova) {
		long elapsedTime = 0;
		try {
			long startTime = System.currentTimeMillis();
			
			Query q = db.query();
			q.constrain(Member.class);
			q.descend("rentedBooks").descend("year").constrain(getRandom(100));
			ObjectSet<Member> result = q.execute();
			if (result.hasNext()) {
				Member m = result.next();
				m.setFirstName("New_name");
				db.store(m);
				db.commit();
				System.out.println("db40: " + m.getFirstName());
			}
			
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
		} catch (Exception e) {
			e.printStackTrace();
			db.close();
		}
		return elapsedTime;
	}
	
	public long delete_N_to_N(int brojSlogova) {
		long elapsedTime = 0;
		try {
			long startTime = System.currentTimeMillis();
			String bookTitle = "Book_"+getRandom(brojSlogova);
			Query q = db.query();
			q.constrain(Member.class);
			q.descend("rentedBooks").descend("title").constrain(bookTitle);
			ObjectSet<Member> result = q.execute();
			if (result.hasNext()) {
				Member m = result.next();
				Book book = m.returnBookByTitle(bookTitle);
				m.returnARentedBook(book);
				db.delete(book);
				db.store(m);
			}
			db.commit();
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
		} catch (Exception e) {
			e.printStackTrace();
			db.close();
		}
		return elapsedTime;
	}
	
	private int getRandom(int max){
		Random r = new Random();
        return r.nextInt(max); 
	}
	
	public void clear_1_on_1(){
		deleteSpecific(Employee.class);
		db.commit();
		deleteSpecific(Address.class);
		db.commit();
	}
	
	public void clear_1_on_N(){

		deleteSpecific(Author.class);
		db.commit();
		deleteSpecific(Book.class);
		db.commit();
	}
	
	public void clear_N_on_N(){
		deleteSpecific(Member.class);
		db.commit();
		deleteSpecific(Book.class);
		db.commit();
	}
}
